<!DOCTYPE html>
<html lang="en">

<head>
  <base href="https://git-scm.com/book/zh/v2/Git-%E5%86%85%E9%83%A8%E5%8E%9F%E7%90%86-Git-%E5%AF%B9%E8%B1%A1" />
  <meta charset='utf-8'>
  <meta content='IE=edge,chrome=1' http-equiv='X-UA-Compatible'>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Git - Git 对象</title>

  <link href='/favicon.ico' rel='shortcut icon' type='image/x-icon'>

  <link rel="stylesheet" media="screen" href="/assets/application-a058ab010d6f86a86903175bbfdaac30ef6057e5901875616753328abbf98b2c.css" />
  <script src="/assets/modernize-b3ebe0c31c24f230dc62179d3e1030d2e57a53b1668d9382c0a27dbd44a94beb.js"></script>
  <!--[if (gte IE 6)&(lte IE 8)]>
  <script src="/javascripts/selectivizr-min.js"></script>
  <![endif]-->

</head>

<body id="documentation">

  <div class="inner">
    <header>

  <a href="/"><img src="/images/logo@2x.png" width="110" height="46" alt="Git" /></a>
  <span id="tagline"></span>
  <script type="text/javascript">
    var taglines = ["fast-version-control","everything-is-local","distributed-even-if-your-workflow-isnt","local-branching-on-the-cheap","distributed-is-the-new-centralized"];
    var tagline = taglines[Math.floor(Math.random() * taglines.length)];
    document.getElementById('tagline').innerHTML = '--' + tagline;
  </script>
  <form id="search" action="/search/results">
    <input id="search-text" name="search" placeholder="Search entire site..." autocomplete="off" type="text" />
  </form>
  <div id="search-results"></div>

</header>

  </div> <!-- .inner -->

    <div class="inner">
      <div id="content-wrapper">
        <button class="sidebar-btn"></button>
<aside class="sidebar" id="sidebar">
  <nav>
    <ul>
      <li>
        <a href="/about">About</a>
        <ul class="">
          <li>
            <a href="/about">Branching and Merging</a>
          </li>
          <li>
            <a href="/about/small-and-fast">Small and Fast</a>
          </li>
          <li>
            <a href="/about/distributed">Distributed</a>
          </li>
          <li>
            <a href="/about/info-assurance">Data Assurance</a>
          </li>
          <li>
            <a href="/about/staging-area">Staging Area</a>
          </li>
          <li>
            <a href="/about/free-and-open-source">Free and Open Source</a>
          </li>
          <li>
            <a href="/about/trademark">Trademark</a>
          </li>
        </ul>
      </li>
      <li>
        <a class="active" href="/doc">Documentation</a>
        <ul class="expanded">
          <li>
            <a href="/docs">Reference</a>
          </li>
          <li>
            <a class="active" href="/book">Book</a>
          </li>
          <li>
            <a href="/videos">Videos</a>
          </li>
          <li>
            <a href="/doc/ext">External Links</a>
          </li>
        </ul>
      </li>
      <li>
        <a href="/downloads">Downloads</a>
        <ul class="">
          <li>
            <a href="/downloads/guis">GUI Clients</a>
          </li>
          <li>
            <a href="/downloads/logos">Logos</a>
          </li>
        </ul>
      </li>
      <li>
        <a href="/community">Community</a>
      </li>
    </ul>
      <hr class="sidebar">
        <p>
This book is available in
  <a href="/book/en">English</a>.
</p>
<p>
  Full translation available in
  <table>
    <tr><td><a href="/book/az">azərbaycan dili</a>,</td></tr>
    <tr><td><a href="/book/bg">български език</a>,</td></tr>
    <tr><td><a href="/book/de">Deutsch</a>,</td></tr>
    <tr><td><a href="/book/es">Español</a>,</td></tr>
    <tr><td><a href="/book/fr">Français</a>,</td></tr>
    <tr><td><a href="/book/gr">Ελληνικά</a>,</td></tr>
    <tr><td><a href="/book/ja">日本語</a>,</td></tr>
    <tr><td><a href="/book/ko">한국어</a>,</td></tr>
    <tr><td><a href="/book/nl">Nederlands</a>,</td></tr>
    <tr><td><a href="/book/ru">Русский</a>,</td></tr>
    <tr><td><a href="/book/sl">Slovenščina</a>,</td></tr>
    <tr><td><a href="/book/tl">Tagalog</a>,</td></tr>
    <tr><td><a href="/book/uk">Українська</a></td></tr>
    <tr><td><a href="/book/zh">简体中文</a>,</td></tr>
  </table>
</p>
<p>
  Partial translations available in
  <table>
    <tr><td><a href="/book/cs">Čeština</a>,</td></tr>
    <tr><td><a href="/book/mk">Македонски</a>,</td></tr>
    <tr><td><a href="/book/pl">Polski</a>,</td></tr>
    <tr><td><a href="/book/sr">Српски</a>,</td></tr>
    <tr><td><a href="/book/uz">Ўзбекча</a>,</td></tr>
    <tr><td><a href="/book/zh-tw">繁體中文</a>,</td></tr>
  </table>
</p>
<p>
  Translations started for
  <table>
    <tr><td><a href="/book/be">Беларуская</a>,</td></tr>
    <tr><td><a href="/book/fa" dir="rtl">فارسی</a>,</td></tr>
    <tr><td><a href="/book/id">Indonesian</a>,</td></tr>
    <tr><td><a href="/book/it">Italiano</a>,</td></tr>
    <tr><td><a href="/book/ms">Bahasa Melayu</a>,</td></tr>
    <tr><td><a href="/book/pt-br">Português (Brasil)</a>,</td></tr>
    <tr><td><a href="/book/pt-pt">Português (Portugal)</a>,</td></tr>
    <tr><td><a href="/book/sv">Svenska</a>,</td></tr>
    <tr><td><a href="/book/tr">Türkçe</a>.</td></tr>
  </table>
</p>
<hr class="sidebar"/>
<p>
The source of this book is  <a href="https://github.com/progit/progit2-zh">hosted on GitHub.</a></br>
Patches, suggestions and comments are welcome.
</p>


  </nav>
</aside>

        <div id="content">
          

<div id='book-chapters'>
  <a class="dropdown-trigger" id="book-chapters-trigger" data-panel-id="chapters-dropdown" href="#">Chapters ▾</a>
<div class='dropdown-panel' id='chapters-dropdown'>
  <div class="three-column">
    <div class='column-left'>
      <ol class='book-toc'>
  <li class='chapter'>
  <h2>1. <a href="/book/zh/v2/%E8%B5%B7%E6%AD%A5-%E5%85%B3%E4%BA%8E%E7%89%88%E6%9C%AC%E6%8E%A7%E5%88%B6">起步</a></h2>
    <ol>
        <li>
          1.1
          <a href="/book/zh/v2/%E8%B5%B7%E6%AD%A5-%E5%85%B3%E4%BA%8E%E7%89%88%E6%9C%AC%E6%8E%A7%E5%88%B6" >关于版本控制 </a>
        </li>
        <li>
          1.2
          <a href="/book/zh/v2/%E8%B5%B7%E6%AD%A5-Git-%E7%AE%80%E5%8F%B2" >Git 简史 </a>
        </li>
        <li>
          1.3
          <a href="/book/zh/v2/%E8%B5%B7%E6%AD%A5-Git-%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9F" >Git 是什么？ </a>
        </li>
        <li>
          1.4
          <a href="/book/zh/v2/%E8%B5%B7%E6%AD%A5-%E5%91%BD%E4%BB%A4%E8%A1%8C" >命令行 </a>
        </li>
        <li>
          1.5
          <a href="/book/zh/v2/%E8%B5%B7%E6%AD%A5-%E5%AE%89%E8%A3%85-Git" >安装 Git </a>
        </li>
        <li>
          1.6
          <a href="/book/zh/v2/%E8%B5%B7%E6%AD%A5-%E5%88%9D%E6%AC%A1%E8%BF%90%E8%A1%8C-Git-%E5%89%8D%E7%9A%84%E9%85%8D%E7%BD%AE" >初次运行 Git 前的配置 </a>
        </li>
        <li>
          1.7
          <a href="/book/zh/v2/%E8%B5%B7%E6%AD%A5-%E8%8E%B7%E5%8F%96%E5%B8%AE%E5%8A%A9" >获取帮助 </a>
        </li>
        <li>
          1.8
          <a href="/book/zh/v2/%E8%B5%B7%E6%AD%A5-%E6%80%BB%E7%BB%93" >总结 </a>
        </li>
    </ol>
  </li>
  <li class='chapter'>
  <h2>2. <a href="/book/zh/v2/Git-%E5%9F%BA%E7%A1%80-%E8%8E%B7%E5%8F%96-Git-%E4%BB%93%E5%BA%93">Git 基础</a></h2>
    <ol>
        <li>
          2.1
          <a href="/book/zh/v2/Git-%E5%9F%BA%E7%A1%80-%E8%8E%B7%E5%8F%96-Git-%E4%BB%93%E5%BA%93" >获取 Git 仓库 </a>
        </li>
        <li>
          2.2
          <a href="/book/zh/v2/Git-%E5%9F%BA%E7%A1%80-%E8%AE%B0%E5%BD%95%E6%AF%8F%E6%AC%A1%E6%9B%B4%E6%96%B0%E5%88%B0%E4%BB%93%E5%BA%93" >记录每次更新到仓库 </a>
        </li>
        <li>
          2.3
          <a href="/book/zh/v2/Git-%E5%9F%BA%E7%A1%80-%E6%9F%A5%E7%9C%8B%E6%8F%90%E4%BA%A4%E5%8E%86%E5%8F%B2" >查看提交历史 </a>
        </li>
        <li>
          2.4
          <a href="/book/zh/v2/Git-%E5%9F%BA%E7%A1%80-%E6%92%A4%E6%B6%88%E6%93%8D%E4%BD%9C" >撤消操作 </a>
        </li>
        <li>
          2.5
          <a href="/book/zh/v2/Git-%E5%9F%BA%E7%A1%80-%E8%BF%9C%E7%A8%8B%E4%BB%93%E5%BA%93%E7%9A%84%E4%BD%BF%E7%94%A8" >远程仓库的使用 </a>
        </li>
        <li>
          2.6
          <a href="/book/zh/v2/Git-%E5%9F%BA%E7%A1%80-%E6%89%93%E6%A0%87%E7%AD%BE" >打标签 </a>
        </li>
        <li>
          2.7
          <a href="/book/zh/v2/Git-%E5%9F%BA%E7%A1%80-Git-%E5%88%AB%E5%90%8D" >Git 别名 </a>
        </li>
        <li>
          2.8
          <a href="/book/zh/v2/Git-%E5%9F%BA%E7%A1%80-%E6%80%BB%E7%BB%93" >总结 </a>
        </li>
    </ol>
  </li>
  <li class='chapter'>
  <h2>3. <a href="/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E5%88%86%E6%94%AF%E7%AE%80%E4%BB%8B">Git 分支</a></h2>
    <ol>
        <li>
          3.1
          <a href="/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E5%88%86%E6%94%AF%E7%AE%80%E4%BB%8B" >分支简介 </a>
        </li>
        <li>
          3.2
          <a href="/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E5%88%86%E6%94%AF%E7%9A%84%E6%96%B0%E5%BB%BA%E4%B8%8E%E5%90%88%E5%B9%B6" >分支的新建与合并 </a>
        </li>
        <li>
          3.3
          <a href="/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E5%88%86%E6%94%AF%E7%AE%A1%E7%90%86" >分支管理 </a>
        </li>
        <li>
          3.4
          <a href="/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E5%88%86%E6%94%AF%E5%BC%80%E5%8F%91%E5%B7%A5%E4%BD%9C%E6%B5%81" >分支开发工作流 </a>
        </li>
        <li>
          3.5
          <a href="/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E8%BF%9C%E7%A8%8B%E5%88%86%E6%94%AF" >远程分支 </a>
        </li>
        <li>
          3.6
          <a href="/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E5%8F%98%E5%9F%BA" >变基 </a>
        </li>
        <li>
          3.7
          <a href="/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E6%80%BB%E7%BB%93" >总结 </a>
        </li>
    </ol>
  </li>
  <li class='chapter'>
  <h2>4. <a href="/book/zh/v2/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E7%9A%84-Git-%E5%8D%8F%E8%AE%AE">服务器上的 Git</a></h2>
    <ol>
        <li>
          4.1
          <a href="/book/zh/v2/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E7%9A%84-Git-%E5%8D%8F%E8%AE%AE" >协议 </a>
        </li>
        <li>
          4.2
          <a href="/book/zh/v2/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E7%9A%84-Git-%E5%9C%A8%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E6%90%AD%E5%BB%BA-Git" >在服务器上搭建 Git </a>
        </li>
        <li>
          4.3
          <a href="/book/zh/v2/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E7%9A%84-Git-%E7%94%9F%E6%88%90-SSH-%E5%85%AC%E9%92%A5" >生成 SSH 公钥 </a>
        </li>
        <li>
          4.4
          <a href="/book/zh/v2/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E7%9A%84-Git-%E9%85%8D%E7%BD%AE%E6%9C%8D%E5%8A%A1%E5%99%A8" >配置服务器 </a>
        </li>
        <li>
          4.5
          <a href="/book/zh/v2/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E7%9A%84-Git-Git-%E5%AE%88%E6%8A%A4%E8%BF%9B%E7%A8%8B" >Git 守护进程 </a>
        </li>
        <li>
          4.6
          <a href="/book/zh/v2/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E7%9A%84-Git-Smart-HTTP" >Smart HTTP </a>
        </li>
        <li>
          4.7
          <a href="/book/zh/v2/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E7%9A%84-Git-GitWeb" >GitWeb </a>
        </li>
        <li>
          4.8
          <a href="/book/zh/v2/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E7%9A%84-Git-GitLab" >GitLab </a>
        </li>
        <li>
          4.9
          <a href="/book/zh/v2/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E7%9A%84-Git-%E7%AC%AC%E4%B8%89%E6%96%B9%E6%89%98%E7%AE%A1%E7%9A%84%E9%80%89%E6%8B%A9" >第三方托管的选择 </a>
        </li>
        <li>
          4.10
          <a href="/book/zh/v2/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E7%9A%84-Git-%E6%80%BB%E7%BB%93" >总结 </a>
        </li>
    </ol>
  </li>
  <li class='chapter'>
  <h2>5. <a href="/book/zh/v2/%E5%88%86%E5%B8%83%E5%BC%8F-Git-%E5%88%86%E5%B8%83%E5%BC%8F%E5%B7%A5%E4%BD%9C%E6%B5%81%E7%A8%8B">分布式 Git</a></h2>
    <ol>
        <li>
          5.1
          <a href="/book/zh/v2/%E5%88%86%E5%B8%83%E5%BC%8F-Git-%E5%88%86%E5%B8%83%E5%BC%8F%E5%B7%A5%E4%BD%9C%E6%B5%81%E7%A8%8B" >分布式工作流程 </a>
        </li>
        <li>
          5.2
          <a href="/book/zh/v2/%E5%88%86%E5%B8%83%E5%BC%8F-Git-%E5%90%91%E4%B8%80%E4%B8%AA%E9%A1%B9%E7%9B%AE%E8%B4%A1%E7%8C%AE" >向一个项目贡献 </a>
        </li>
        <li>
          5.3
          <a href="/book/zh/v2/%E5%88%86%E5%B8%83%E5%BC%8F-Git-%E7%BB%B4%E6%8A%A4%E9%A1%B9%E7%9B%AE" >维护项目 </a>
        </li>
        <li>
          5.4
          <a href="/book/zh/v2/%E5%88%86%E5%B8%83%E5%BC%8F-Git-%E6%80%BB%E7%BB%93" >总结 </a>
        </li>
    </ol>
  </li>
</ol>

    </div>
    <div class='column-middle'>
      <ol class='book-toc'>
  <li class='chapter'>
  <h2>6. <a href="/book/zh/v2/GitHub-%E8%B4%A6%E6%88%B7%E7%9A%84%E5%88%9B%E5%BB%BA%E5%92%8C%E9%85%8D%E7%BD%AE">GitHub</a></h2>
    <ol>
        <li>
          6.1
          <a href="/book/zh/v2/GitHub-%E8%B4%A6%E6%88%B7%E7%9A%84%E5%88%9B%E5%BB%BA%E5%92%8C%E9%85%8D%E7%BD%AE" >账户的创建和配置 </a>
        </li>
        <li>
          6.2
          <a href="/book/zh/v2/GitHub-%E5%AF%B9%E9%A1%B9%E7%9B%AE%E5%81%9A%E5%87%BA%E8%B4%A1%E7%8C%AE" >对项目做出贡献 </a>
        </li>
        <li>
          6.3
          <a href="/book/zh/v2/GitHub-%E7%BB%B4%E6%8A%A4%E9%A1%B9%E7%9B%AE" >维护项目 </a>
        </li>
        <li>
          6.4
          <a href="/book/zh/v2/GitHub-%E7%AE%A1%E7%90%86%E7%BB%84%E7%BB%87" >管理组织 </a>
        </li>
        <li>
          6.5
          <a href="/book/zh/v2/GitHub-%E8%84%9A%E6%9C%AC-GitHub" >脚本 GitHub </a>
        </li>
        <li>
          6.6
          <a href="/book/zh/v2/GitHub-%E6%80%BB%E7%BB%93" >总结 </a>
        </li>
    </ol>
  </li>
  <li class='chapter'>
  <h2>7. <a href="/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E9%80%89%E6%8B%A9%E4%BF%AE%E8%AE%A2%E7%89%88%E6%9C%AC">Git 工具</a></h2>
    <ol>
        <li>
          7.1
          <a href="/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E9%80%89%E6%8B%A9%E4%BF%AE%E8%AE%A2%E7%89%88%E6%9C%AC" >选择修订版本 </a>
        </li>
        <li>
          7.2
          <a href="/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E4%BA%A4%E4%BA%92%E5%BC%8F%E6%9A%82%E5%AD%98" >交互式暂存 </a>
        </li>
        <li>
          7.3
          <a href="/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E8%B4%AE%E8%97%8F%E4%B8%8E%E6%B8%85%E7%90%86" >贮藏与清理 </a>
        </li>
        <li>
          7.4
          <a href="/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E7%AD%BE%E7%BD%B2%E5%B7%A5%E4%BD%9C" >签署工作 </a>
        </li>
        <li>
          7.5
          <a href="/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E6%90%9C%E7%B4%A2" >搜索 </a>
        </li>
        <li>
          7.6
          <a href="/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E9%87%8D%E5%86%99%E5%8E%86%E5%8F%B2" >重写历史 </a>
        </li>
        <li>
          7.7
          <a href="/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E9%87%8D%E7%BD%AE%E6%8F%AD%E5%AF%86" >重置揭密 </a>
        </li>
        <li>
          7.8
          <a href="/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E9%AB%98%E7%BA%A7%E5%90%88%E5%B9%B6" >高级合并 </a>
        </li>
        <li>
          7.9
          <a href="/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-Rerere" >Rerere </a>
        </li>
        <li>
          7.10
          <a href="/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E4%BD%BF%E7%94%A8-Git-%E8%B0%83%E8%AF%95" >使用 Git 调试 </a>
        </li>
        <li>
          7.11
          <a href="/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E5%AD%90%E6%A8%A1%E5%9D%97" >子模块 </a>
        </li>
        <li>
          7.12
          <a href="/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E6%89%93%E5%8C%85" >打包 </a>
        </li>
        <li>
          7.13
          <a href="/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E6%9B%BF%E6%8D%A2" >替换 </a>
        </li>
        <li>
          7.14
          <a href="/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E5%87%AD%E8%AF%81%E5%AD%98%E5%82%A8" >凭证存储 </a>
        </li>
        <li>
          7.15
          <a href="/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E6%80%BB%E7%BB%93" >总结 </a>
        </li>
    </ol>
  </li>
  <li class='chapter'>
  <h2>8. <a href="/book/zh/v2/%E8%87%AA%E5%AE%9A%E4%B9%89-Git-%E9%85%8D%E7%BD%AE-Git">自定义 Git</a></h2>
    <ol>
        <li>
          8.1
          <a href="/book/zh/v2/%E8%87%AA%E5%AE%9A%E4%B9%89-Git-%E9%85%8D%E7%BD%AE-Git" >配置 Git </a>
        </li>
        <li>
          8.2
          <a href="/book/zh/v2/%E8%87%AA%E5%AE%9A%E4%B9%89-Git-Git-%E5%B1%9E%E6%80%A7" >Git 属性 </a>
        </li>
        <li>
          8.3
          <a href="/book/zh/v2/%E8%87%AA%E5%AE%9A%E4%B9%89-Git-Git-%E9%92%A9%E5%AD%90" >Git 钩子 </a>
        </li>
        <li>
          8.4
          <a href="/book/zh/v2/%E8%87%AA%E5%AE%9A%E4%B9%89-Git-%E4%BD%BF%E7%94%A8%E5%BC%BA%E5%88%B6%E7%AD%96%E7%95%A5%E7%9A%84%E4%B8%80%E4%B8%AA%E4%BE%8B%E5%AD%90" >使用强制策略的一个例子 </a>
        </li>
        <li>
          8.5
          <a href="/book/zh/v2/%E8%87%AA%E5%AE%9A%E4%B9%89-Git-%E6%80%BB%E7%BB%93" >总结 </a>
        </li>
    </ol>
  </li>
  <li class='chapter'>
  <h2>9. <a href="/book/zh/v2/Git-%E4%B8%8E%E5%85%B6%E4%BB%96%E7%B3%BB%E7%BB%9F-%E4%BD%9C%E4%B8%BA%E5%AE%A2%E6%88%B7%E7%AB%AF%E7%9A%84-Git">Git 与其他系统</a></h2>
    <ol>
        <li>
          9.1
          <a href="/book/zh/v2/Git-%E4%B8%8E%E5%85%B6%E4%BB%96%E7%B3%BB%E7%BB%9F-%E4%BD%9C%E4%B8%BA%E5%AE%A2%E6%88%B7%E7%AB%AF%E7%9A%84-Git" >作为客户端的 Git </a>
        </li>
        <li>
          9.2
          <a href="/book/zh/v2/Git-%E4%B8%8E%E5%85%B6%E4%BB%96%E7%B3%BB%E7%BB%9F-%E8%BF%81%E7%A7%BB%E5%88%B0-Git" >迁移到 Git </a>
        </li>
        <li>
          9.3
          <a href="/book/zh/v2/Git-%E4%B8%8E%E5%85%B6%E4%BB%96%E7%B3%BB%E7%BB%9F-%E6%80%BB%E7%BB%93" >总结 </a>
        </li>
    </ol>
  </li>
  <li class='chapter'>
  <h2>10. <a href="/book/zh/v2/Git-%E5%86%85%E9%83%A8%E5%8E%9F%E7%90%86-%E5%BA%95%E5%B1%82%E5%91%BD%E4%BB%A4%E4%B8%8E%E4%B8%8A%E5%B1%82%E5%91%BD%E4%BB%A4">Git 内部原理</a></h2>
    <ol>
        <li>
          10.1
          <a href="/book/zh/v2/Git-%E5%86%85%E9%83%A8%E5%8E%9F%E7%90%86-%E5%BA%95%E5%B1%82%E5%91%BD%E4%BB%A4%E4%B8%8E%E4%B8%8A%E5%B1%82%E5%91%BD%E4%BB%A4" >底层命令与上层命令 </a>
        </li>
        <li>
          10.2
          <a href="/book/zh/v2/Git-%E5%86%85%E9%83%A8%E5%8E%9F%E7%90%86-Git-%E5%AF%B9%E8%B1%A1" class=active>Git 对象 </a>
        </li>
        <li>
          10.3
          <a href="/book/zh/v2/Git-%E5%86%85%E9%83%A8%E5%8E%9F%E7%90%86-Git-%E5%BC%95%E7%94%A8" >Git 引用 </a>
        </li>
        <li>
          10.4
          <a href="/book/zh/v2/Git-%E5%86%85%E9%83%A8%E5%8E%9F%E7%90%86-%E5%8C%85%E6%96%87%E4%BB%B6" >包文件 </a>
        </li>
        <li>
          10.5
          <a href="/book/zh/v2/Git-%E5%86%85%E9%83%A8%E5%8E%9F%E7%90%86-%E5%BC%95%E7%94%A8%E8%A7%84%E8%8C%83" >引用规范 </a>
        </li>
        <li>
          10.6
          <a href="/book/zh/v2/Git-%E5%86%85%E9%83%A8%E5%8E%9F%E7%90%86-%E4%BC%A0%E8%BE%93%E5%8D%8F%E8%AE%AE" >传输协议 </a>
        </li>
        <li>
          10.7
          <a href="/book/zh/v2/Git-%E5%86%85%E9%83%A8%E5%8E%9F%E7%90%86-%E7%BB%B4%E6%8A%A4%E4%B8%8E%E6%95%B0%E6%8D%AE%E6%81%A2%E5%A4%8D" >维护与数据恢复 </a>
        </li>
        <li>
          10.8
          <a href="/book/zh/v2/Git-%E5%86%85%E9%83%A8%E5%8E%9F%E7%90%86-%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F" >环境变量 </a>
        </li>
        <li>
          10.9
          <a href="/book/zh/v2/Git-%E5%86%85%E9%83%A8%E5%8E%9F%E7%90%86-%E6%80%BB%E7%BB%93" >总结 </a>
        </li>
    </ol>
  </li>
</ol>

    </div>
    <div class='column-right'>
      <ol class='book-toc'>
  <li class='chapter'>
  <h2>A1. <a href="/book/zh/v2/%E9%99%84%E5%BD%95-A%3A-%E5%9C%A8%E5%85%B6%E5%AE%83%E7%8E%AF%E5%A2%83%E4%B8%AD%E4%BD%BF%E7%94%A8-Git-%E5%9B%BE%E5%BD%A2%E7%95%8C%E9%9D%A2">附录 A: 在其它环境中使用 Git</a></h2>
    <ol>
        <li>
          A1.1
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-A%3A-%E5%9C%A8%E5%85%B6%E5%AE%83%E7%8E%AF%E5%A2%83%E4%B8%AD%E4%BD%BF%E7%94%A8-Git-%E5%9B%BE%E5%BD%A2%E7%95%8C%E9%9D%A2" >图形界面 </a>
        </li>
        <li>
          A1.2
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-A%3A-%E5%9C%A8%E5%85%B6%E5%AE%83%E7%8E%AF%E5%A2%83%E4%B8%AD%E4%BD%BF%E7%94%A8-Git-Visual-Studio-%E4%B8%AD%E7%9A%84-Git" >Visual Studio 中的 Git </a>
        </li>
        <li>
          A1.3
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-A%3A-%E5%9C%A8%E5%85%B6%E5%AE%83%E7%8E%AF%E5%A2%83%E4%B8%AD%E4%BD%BF%E7%94%A8-Git-Visual-Studio-Code-%E4%B8%AD%E7%9A%84-Git" >Visual Studio Code 中的 Git </a>
        </li>
        <li>
          A1.4
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-A%3A-%E5%9C%A8%E5%85%B6%E5%AE%83%E7%8E%AF%E5%A2%83%E4%B8%AD%E4%BD%BF%E7%94%A8-Git-Eclipse-%E4%B8%AD%E7%9A%84-Git" >Eclipse 中的 Git </a>
        </li>
        <li>
          A1.5
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-A%3A-%E5%9C%A8%E5%85%B6%E5%AE%83%E7%8E%AF%E5%A2%83%E4%B8%AD%E4%BD%BF%E7%94%A8-Git-IntelliJ-%2F-PyCharm-%2F-WebStorm-%2F-PhpStorm-%2F-RubyMine-%E4%B8%AD%E7%9A%84-Git" >IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine 中的 Git </a>
        </li>
        <li>
          A1.6
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-A%3A-%E5%9C%A8%E5%85%B6%E5%AE%83%E7%8E%AF%E5%A2%83%E4%B8%AD%E4%BD%BF%E7%94%A8-Git-Sublime-Text-%E4%B8%AD%E7%9A%84-Git" >Sublime Text 中的 Git </a>
        </li>
        <li>
          A1.7
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-A%3A-%E5%9C%A8%E5%85%B6%E5%AE%83%E7%8E%AF%E5%A2%83%E4%B8%AD%E4%BD%BF%E7%94%A8-Git-Bash-%E4%B8%AD%E7%9A%84-Git" >Bash 中的 Git </a>
        </li>
        <li>
          A1.8
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-A%3A-%E5%9C%A8%E5%85%B6%E5%AE%83%E7%8E%AF%E5%A2%83%E4%B8%AD%E4%BD%BF%E7%94%A8-Git-Zsh-%E4%B8%AD%E7%9A%84-Git" >Zsh 中的 Git </a>
        </li>
        <li>
          A1.9
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-A%3A-%E5%9C%A8%E5%85%B6%E5%AE%83%E7%8E%AF%E5%A2%83%E4%B8%AD%E4%BD%BF%E7%94%A8-Git-Git-%E5%9C%A8-PowerShell-%E4%B8%AD%E4%BD%BF%E7%94%A8-Git" >Git 在 PowerShell 中使用 Git </a>
        </li>
        <li>
          A1.10
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-A%3A-%E5%9C%A8%E5%85%B6%E5%AE%83%E7%8E%AF%E5%A2%83%E4%B8%AD%E4%BD%BF%E7%94%A8-Git-%E6%80%BB%E7%BB%93" >总结 </a>
        </li>
    </ol>
  </li>
  <li class='chapter'>
  <h2>A2. <a href="/book/zh/v2/%E9%99%84%E5%BD%95-B%3A-%E5%9C%A8%E4%BD%A0%E7%9A%84%E5%BA%94%E7%94%A8%E4%B8%AD%E5%B5%8C%E5%85%A5-Git-%E5%91%BD%E4%BB%A4%E8%A1%8C-Git-%E6%96%B9%E5%BC%8F">附录 B: 在你的应用中嵌入 Git</a></h2>
    <ol>
        <li>
          A2.1
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-B%3A-%E5%9C%A8%E4%BD%A0%E7%9A%84%E5%BA%94%E7%94%A8%E4%B8%AD%E5%B5%8C%E5%85%A5-Git-%E5%91%BD%E4%BB%A4%E8%A1%8C-Git-%E6%96%B9%E5%BC%8F" >命令行 Git 方式 </a>
        </li>
        <li>
          A2.2
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-B%3A-%E5%9C%A8%E4%BD%A0%E7%9A%84%E5%BA%94%E7%94%A8%E4%B8%AD%E5%B5%8C%E5%85%A5-Git-Libgit2" >Libgit2 </a>
        </li>
        <li>
          A2.3
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-B%3A-%E5%9C%A8%E4%BD%A0%E7%9A%84%E5%BA%94%E7%94%A8%E4%B8%AD%E5%B5%8C%E5%85%A5-Git-JGit" >JGit </a>
        </li>
        <li>
          A2.4
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-B%3A-%E5%9C%A8%E4%BD%A0%E7%9A%84%E5%BA%94%E7%94%A8%E4%B8%AD%E5%B5%8C%E5%85%A5-Git-go-git" >go-git </a>
        </li>
        <li>
          A2.5
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-B%3A-%E5%9C%A8%E4%BD%A0%E7%9A%84%E5%BA%94%E7%94%A8%E4%B8%AD%E5%B5%8C%E5%85%A5-Git-Dulwich" >Dulwich </a>
        </li>
    </ol>
  </li>
  <li class='chapter'>
  <h2>A3. <a href="/book/zh/v2/%E9%99%84%E5%BD%95-C%3A-Git-%E5%91%BD%E4%BB%A4-%E8%AE%BE%E7%BD%AE%E4%B8%8E%E9%85%8D%E7%BD%AE">附录 C: Git 命令</a></h2>
    <ol>
        <li>
          A3.1
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-C%3A-Git-%E5%91%BD%E4%BB%A4-%E8%AE%BE%E7%BD%AE%E4%B8%8E%E9%85%8D%E7%BD%AE" >设置与配置 </a>
        </li>
        <li>
          A3.2
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-C%3A-Git-%E5%91%BD%E4%BB%A4-%E8%8E%B7%E5%8F%96%E4%B8%8E%E5%88%9B%E5%BB%BA%E9%A1%B9%E7%9B%AE" >获取与创建项目 </a>
        </li>
        <li>
          A3.3
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-C%3A-Git-%E5%91%BD%E4%BB%A4-%E5%BF%AB%E7%85%A7%E5%9F%BA%E7%A1%80" >快照基础 </a>
        </li>
        <li>
          A3.4
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-C%3A-Git-%E5%91%BD%E4%BB%A4-%E5%88%86%E6%94%AF%E4%B8%8E%E5%90%88%E5%B9%B6" >分支与合并 </a>
        </li>
        <li>
          A3.5
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-C%3A-Git-%E5%91%BD%E4%BB%A4-%E9%A1%B9%E7%9B%AE%E5%88%86%E4%BA%AB%E4%B8%8E%E6%9B%B4%E6%96%B0" >项目分享与更新 </a>
        </li>
        <li>
          A3.6
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-C%3A-Git-%E5%91%BD%E4%BB%A4-%E6%A3%80%E6%9F%A5%E4%B8%8E%E6%AF%94%E8%BE%83" >检查与比较 </a>
        </li>
        <li>
          A3.7
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-C%3A-Git-%E5%91%BD%E4%BB%A4-%E8%B0%83%E8%AF%95" >调试 </a>
        </li>
        <li>
          A3.8
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-C%3A-Git-%E5%91%BD%E4%BB%A4-%E8%A1%A5%E4%B8%81" >补丁 </a>
        </li>
        <li>
          A3.9
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-C%3A-Git-%E5%91%BD%E4%BB%A4-%E9%82%AE%E4%BB%B6" >邮件 </a>
        </li>
        <li>
          A3.10
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-C%3A-Git-%E5%91%BD%E4%BB%A4-%E5%A4%96%E9%83%A8%E7%B3%BB%E7%BB%9F" >外部系统 </a>
        </li>
        <li>
          A3.11
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-C%3A-Git-%E5%91%BD%E4%BB%A4-%E7%AE%A1%E7%90%86" >管理 </a>
        </li>
        <li>
          A3.12
          <a href="/book/zh/v2/%E9%99%84%E5%BD%95-C%3A-Git-%E5%91%BD%E4%BB%A4-%E5%BA%95%E5%B1%82%E5%91%BD%E4%BB%A4" >底层命令 </a>
        </li>
    </ol>
  </li>
</ol>

    </div>
  </div>
 </div>

    <span class="light" id="edition">
      2nd Edition
    </span>
</div>

<div id='main' class="book edition2">
    <h1>10.2 Git 内部原理 - Git 对象</h1>
  <div>
<h2 id="_objects">Git 对象</h2>
<div class="paragraph">
<p>Git 是一个内容寻址文件系统，听起来很酷。但这是什么意思呢？
这意味着，Git 的核心部分是一个简单的键值对数据库（key-value data store）。
你可以向 Git 仓库中插入任意类型的内容，它会返回一个唯一的键，通过该键可以在任意时刻再次取回该内容。</p>
</div>
<div class="paragraph">
<p>可以通过底层命令 <code>git hash-object</code> 来演示上述效果——该命令可将任意数据保存于
<code>.git/objects</code> 目录（即 <strong>对象数据库</strong>），并返回指向该数据对象的唯一的键。</p>
</div>
<div class="paragraph">
<p>首先，我们需要初始化一个新的 Git 版本库，并确认 <code>objects</code> 目录为空：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ git init test
Initialized empty Git repository in /tmp/test/.git/
$ cd test
$ find .git/objects
.git/objects
.git/objects/info
.git/objects/pack
$ find .git/objects -type f</code></pre>
</div>
</div>
<div class="paragraph">
<p>可以看到 Git 对 <code>objects</code> 目录进行了初始化，并创建了 <code>pack</code> 和 <code>info</code> 子目录，但均为空。
接着，我们用 <code>git hash-object</code> 创建一个新的数据对象并将它手动存入你的新 Git 数据库中：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ echo 'test content' | git hash-object -w --stdin
d670460b4b4aece5915caf5c68d12f560a9fe3e4</code></pre>
</div>
</div>
<div class="paragraph">
<p>在这种最简单的形式中，<code>git hash-object</code> 会接受你传给它的东西，而它只会返回可以存储在 Git 仓库中的唯一键。
<code>-w</code> 选项会指示该命令不要只返回键，还要将该对象写入数据库中。
最后，<code>--stdin</code> 选项则指示该命令从标准输入读取内容；若不指定此选项，则须在命令尾部给出待存储文件的路径。</p>
</div>
<div class="paragraph">
<p>此命令输出一个长度为 40 个字符的校验和。
这是一个 SHA-1 哈希值——一个将待存储的数据外加一个头部信息（header）一起做 SHA-1 校验运算而得的校验和。后文会简要讨论该头部信息。
现在我们可以查看 Git 是如何存储数据的：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ find .git/objects -type f
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4</code></pre>
</div>
</div>
<div class="paragraph">
<p>如果你再次查看 <code>objects</code> 目录，那么可以在其中找到一个与新内容对应的文件。
这就是开始时 Git 存储内容的方式——一个文件对应一条内容，
以该内容加上特定头部信息一起的 SHA-1 校验和为文件命名。
校验和的前两个字符用于命名子目录，余下的 38 个字符则用作文件名。</p>
</div>
<div class="paragraph">
<p>一旦你将内容存储在了对象数据库中，那么可以通过 <code>cat-file</code> 命令从 Git 那里取回数据。
这个命令简直就是一把剖析 Git 对象的瑞士军刀。
为 <code>cat-file</code> 指定 <code>-p</code> 选项可指示该命令自动判断内容的类型，并为我们显示大致的内容：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4
test content</code></pre>
</div>
</div>
<div class="paragraph">
<p>至此，你已经掌握了如何向 Git 中存入内容，以及如何将它们取出。
我们同样可以将这些操作应用于文件中的内容。
例如，可以对一个文件进行简单的版本控制。
首先，创建一个新文件并将其内容存入数据库：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ echo 'version 1' &gt; test.txt
$ git hash-object -w test.txt
83baae61804e65cc73a7201a7252750c76066a30</code></pre>
</div>
</div>
<div class="paragraph">
<p>接着，向文件里写入新内容，并再次将其存入数据库：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ echo 'version 2' &gt; test.txt
$ git hash-object -w test.txt
1f7a7a472abf3dd9643fd615f6da379c4acb3e3a</code></pre>
</div>
</div>
<div class="paragraph">
<p>对象数据库记录下了该文件的两个不同版本，当然之前我们存入的第一条内容也还在：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ find .git/objects -type f
.git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a
.git/objects/83/baae61804e65cc73a7201a7252750c76066a30
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4</code></pre>
</div>
</div>
<div class="paragraph">
<p>现在可以在删掉 <code>test.txt</code> 的本地副本，然后用 Git 从对象数据库中取回它的第一个版本：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ git cat-file -p 83baae61804e65cc73a7201a7252750c76066a30 &gt; test.txt
$ cat test.txt
version 1</code></pre>
</div>
</div>
<div class="paragraph">
<p>或者第二个版本：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ git cat-file -p 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a &gt; test.txt
$ cat test.txt
version 2</code></pre>
</div>
</div>
<div class="paragraph">
<p>然而，记住文件的每一个版本所对应的 SHA-1 值并不现实；另一个问题是，在这个（简单的版本控制）系统中，文件名并没有被保存——我们仅保存了文件的内容。
上述类型的对象我们称之为 <strong>数据对象（blob object）</strong>。
利用 <code>git cat-file -t</code> 命令，可以让 Git 告诉我们其内部存储的任何对象类型，只要给定该对象的 SHA-1 值：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ git cat-file -t 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a
blob</code></pre>
</div>
</div>
<div class="sect3">
<h3 id="_tree_objects">树对象</h3>
<div class="paragraph">
<p>接下来要探讨的 Git 对象类型是树对象（tree object），它能解决文件名保存的问题，也允许我们将多个文件组织到一起。
Git 以一种类似于 UNIX 文件系统的方式存储内容，但作了些许简化。
所有内容均以树对象和数据对象的形式存储，其中树对象对应了 UNIX 中的目录项，数据对象则大致上对应了 inodes 或文件内容。
一个树对象包含了一条或多条树对象记录（tree entry），每条记录含有一个指向数据对象或者子树对象的 SHA-1 指针，以及相应的模式、类型、文件名信息。
例如，某项目当前对应的最新树对象可能是这样的：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ git cat-file -p master^{tree}
100644 blob a906cb2a4a904a152e80877d4088654daad0c859      README
100644 blob 8f94139338f9404f26296befa88755fc2598c289      Rakefile
040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0      lib</code></pre>
</div>
</div>
<div class="paragraph">
<p><code>master^{tree}</code> 语法表示 <code>master</code> 分支上最新的提交所指向的树对象。
请注意，<code>lib</code> 子目录（所对应的那条树对象记录）并不是一个数据对象，而是一个指针，其指向的是另一个树对象：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ git cat-file -p 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0
100644 blob 47c6340d6459e05787f644c2447d2595f5d3a54b      simplegit.rb</code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="paragraph">
<p>你可能会在某些 shell 中使用 <code>master^{tree}</code> 语法时遇到错误。</p>
</div>
<div class="paragraph">
<p>在 Windows 的 CMD 中，字符 <code>^</code> 被用于转义，因此你必须双写它以避免出现问题：<code>git cat-file -p master^^{tree}</code>。
在 PowerShell 中使用字符 {} 时则必须用引号引起来，以此来避免参数解析错误：<code>git cat-file -p 'master^{tree}'</code>。</p>
</div>
<div class="paragraph">
<p>在 ZSH 中，字符 <code>^</code> 被用在通配模式（globbing）中，因此你必须将整个表达式用引号引起来：<code>git cat-file -p "master^{tree}"</code>。</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>从概念上讲，Git 内部存储的数据有点像这样：</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/book/en/v2/images/data-model-1.png" alt="简化版的 Git 数据模型。">
</div>
<div class="title">Figure 149. 简化版的 Git 数据模型。</div>
</div>
<div class="paragraph">
<p>你可以轻松创建自己的树对象。
通常，Git 根据某一时刻暂存区（即 index 区域，下同）所表示的状态创建并记录一个对应的树对象，
如此重复便可依次记录（某个时间段内）一系列的树对象。
因此，为创建一个树对象，首先需要通过暂存一些文件来创建一个暂存区。
可以通过底层命令 <code>git update-index</code> 为一个单独文件——我们的 test.txt 文件的首个版本——创建一个暂存区。
利用该命令，可以把 <code>test.txt</code> 文件的首个版本人为地加入一个新的暂存区。
必须为上述命令指定 <code>--add</code> 选项，因为此前该文件并不在暂存区中（我们甚至都还没来得及创建一个暂存区呢）；
同样必需的还有 <code>--cacheinfo</code> 选项，因为将要添加的文件位于 Git 数据库中，而不是位于当前目录下。
同时，需要指定文件模式、SHA-1 与文件名：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ git update-index --add --cacheinfo 100644 \
  83baae61804e65cc73a7201a7252750c76066a30 test.txt</code></pre>
</div>
</div>
<div class="paragraph">
<p>本例中，我们指定的文件模式为 <code>100644</code>，表明这是一个普通文件。
其他选择包括：<code>100755</code>，表示一个可执行文件；<code>120000</code>，表示一个符号链接。
这里的文件模式参考了常见的 UNIX 文件模式，但远没那么灵活——上述三种模式即是
Git 文件（即数据对象）的所有合法模式（当然，还有其他一些模式，但用于目录项和子模块）。</p>
</div>
<div class="paragraph">
<p>现在，可以通过 <code>git write-tree</code> 命令将暂存区内容写入一个树对象。
此处无需指定 <code>-w</code> 选项——如果某个树对象此前并不存在的话，当调用此命令时，
它会根据当前暂存区状态自动创建一个新的树对象：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ git write-tree
d8329fc1cc938780ffdd9f94e0d364e0ea74f579
$ git cat-file -p d8329fc1cc938780ffdd9f94e0d364e0ea74f579
100644 blob 83baae61804e65cc73a7201a7252750c76066a30      test.txt</code></pre>
</div>
</div>
<div class="paragraph">
<p>不妨用之前见过的 <code>git cat-file</code> 命令验证一下它确实是一个树对象：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ git cat-file -t d8329fc1cc938780ffdd9f94e0d364e0ea74f579
tree</code></pre>
</div>
</div>
<div class="paragraph">
<p>接着我们来创建一个新的树对象，它包括 <code>test.txt</code> 文件的第二个版本，以及一个新的文件：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ echo 'new file' &gt; new.txt
$ git update-index --add --cacheinfo 100644 \
  1f7a7a472abf3dd9643fd615f6da379c4acb3e3a test.txt
$ git update-index --add new.txt</code></pre>
</div>
</div>
<div class="paragraph">
<p>暂存区现在包含了 <code>test.txt</code> 文件的新版本，和一个新文件：<code>new.txt</code>。
记录下这个目录树（将当前暂存区的状态记录为一个树对象），然后观察它的结构：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ git write-tree
0155eb4229851634a0f03eb265b69f5a2d56f341
$ git cat-file -p 0155eb4229851634a0f03eb265b69f5a2d56f341
100644 blob fa49b077972391ad58037050f2a75f74e3671e92      new.txt
100644 blob 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a      test.txt</code></pre>
</div>
</div>
<div class="paragraph">
<p>我们注意到，新的树对象包含两条文件记录，同时 test.txt 的 SHA-1 值（<code>1f7a7a</code>）是先前值的“第二版”。
只是为了好玩：你可以将第一个树对象加入第二个树对象，使其成为新的树对象的一个子目录。
通过调用 <code>git read-tree</code> 命令，可以把树对象读入暂存区。
本例中，可以通过对该命令指定 <code>--prefix</code> 选项，将一个已有的树对象作为子树读入暂存区：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ git read-tree --prefix=bak d8329fc1cc938780ffdd9f94e0d364e0ea74f579
$ git write-tree
3c4e9cd789d88d8d89c1073707c3585e41b0e614
$ git cat-file -p 3c4e9cd789d88d8d89c1073707c3585e41b0e614
040000 tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579      bak
100644 blob fa49b077972391ad58037050f2a75f74e3671e92      new.txt
100644 blob 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a      test.txt</code></pre>
</div>
</div>
<div class="paragraph">
<p>如果基于这个新的树对象创建一个工作目录，你会发现工作目录的根目录包含两个文件以及一个名为
<code>bak</code> 的子目录，该子目录包含 <code>test.txt</code> 文件的第一个版本。
可以认为 Git 内部存储着的用于表示上述结构的数据是这样的：</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/book/en/v2/images/data-model-2.png" alt="当前 Git 的数据内容结构。">
</div>
<div class="title">Figure 150. 当前 Git 的数据内容结构。</div>
</div>
</div>
<div class="sect3">
<h3 id="_git_commit_objects">提交对象</h3>
<div class="paragraph">
<p>如果你做完了以上所有操作，那么现在就有了三个树对象，分别代表我们想要跟踪的不同项目快照。
然而问题依旧：若想重用这些快照，你必须记住所有三个 SHA-1 哈希值。
并且，你也完全不知道是谁保存了这些快照，在什么时刻保存的，以及为什么保存这些快照。
而以上这些，正是提交对象（commit object）能为你保存的基本信息。</p>
</div>
<div class="paragraph">
<p>可以通过调用 <code>commit-tree</code> 命令创建一个提交对象，为此需要指定一个树对象的 SHA-1 值，以及该提交的父提交对象（如果有的话）。
我们从之前创建的第一个树对象开始：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ echo 'first commit' | git commit-tree d8329f
fdf4fc3344e67ab068f836878b6c4951e3b15f3d</code></pre>
</div>
</div>
<div class="paragraph">
<p>由于创建时间和作者数据不同，你现在会得到一个不同的散列值。
请将本章后续内容中的提交和标签的散列值替换为你自己的校验和。
现在可以通过 <code>git cat-file</code> 命令查看这个新提交对象：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ git cat-file -p fdf4fc3
tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579
author Scott Chacon &lt;schacon@gmail.com&gt; 1243040974 -0700
committer Scott Chacon &lt;schacon@gmail.com&gt; 1243040974 -0700

first commit</code></pre>
</div>
</div>
<div class="paragraph">
<p>提交对象的格式很简单：它先指定一个顶层树对象，代表当前项目快照；
然后是可能存在的父提交（前面描述的提交对象并不存在任何父提交）；
之后是作者/提交者信息（依据你的 <code>user.name</code> 和 <code>user.email</code> 配置来设定，外加一个时间戳）；
留空一行，最后是提交注释。</p>
</div>
<div class="paragraph">
<p>接着，我们将创建另两个提交对象，它们分别引用各自的上一个提交（作为其父提交对象）：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ echo 'second commit' | git commit-tree 0155eb -p fdf4fc3
cac0cab538b970a37ea1e769cbbde608743bc96d
$ echo 'third commit'  | git commit-tree 3c4e9c -p cac0cab
1a410efbd13591db07496601ebc7a059dd55cfe9</code></pre>
</div>
</div>
<div class="paragraph">
<p>这三个提交对象分别指向之前创建的三个树对象快照中的一个。
现在，如果对最后一个提交的 SHA-1 值运行 <code>git log</code> 命令，会出乎意料的发现，你已有一个货真价实的、可由 <code>git log</code> 查看的 Git 提交历史了：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ git log --stat 1a410e
commit 1a410efbd13591db07496601ebc7a059dd55cfe9
Author: Scott Chacon &lt;schacon@gmail.com&gt;
Date:   Fri May 22 18:15:24 2009 -0700

	third commit

 bak/test.txt | 1 +
 1 file changed, 1 insertion(+)

commit cac0cab538b970a37ea1e769cbbde608743bc96d
Author: Scott Chacon &lt;schacon@gmail.com&gt;
Date:   Fri May 22 18:14:29 2009 -0700

	second commit

 new.txt  | 1 +
 test.txt | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

commit fdf4fc3344e67ab068f836878b6c4951e3b15f3d
Author: Scott Chacon &lt;schacon@gmail.com&gt;
Date:   Fri May 22 18:09:34 2009 -0700

    first commit

 test.txt | 1 +
 1 file changed, 1 insertion(+)</code></pre>
</div>
</div>
<div class="paragraph">
<p>太神奇了：
就在刚才，你没有借助任何上层命令，仅凭几个底层操作便完成了一个 Git 提交历史的创建。
这就是每次我们运行 <code>git add</code> 和 <code>git commit</code> 命令时，Git 所做的工作实质就是将被改写的文件保存为数据对象，
更新暂存区，记录树对象，最后创建一个指明了顶层树对象和父提交的提交对象。
这三种主要的 Git 对象——数据对象、树对象、提交对象——最初均以单独文件的形式保存在 <code>.git/objects</code> 目录下。
下面列出了目前示例目录内的所有对象，辅以各自所保存内容的注释：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ find .git/objects -type f
.git/objects/01/55eb4229851634a0f03eb265b69f5a2d56f341 # tree 2
.git/objects/1a/410efbd13591db07496601ebc7a059dd55cfe9 # commit 3
.git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a # test.txt v2
.git/objects/3c/4e9cd789d88d8d89c1073707c3585e41b0e614 # tree 3
.git/objects/83/baae61804e65cc73a7201a7252750c76066a30 # test.txt v1
.git/objects/ca/c0cab538b970a37ea1e769cbbde608743bc96d # commit 2
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4 # 'test content'
.git/objects/d8/329fc1cc938780ffdd9f94e0d364e0ea74f579 # tree 1
.git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 # new.txt
.git/objects/fd/f4fc3344e67ab068f836878b6c4951e3b15f3d # commit 1</code></pre>
</div>
</div>
<div class="paragraph">
<p>如果跟踪所有的内部指针，将得到一个类似下面的对象关系图：</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/book/en/v2/images/data-model-3.png" alt="你的 Git 目录下所有可达的对象。">
</div>
<div class="title">Figure 151. 你的 Git 目录下所有可达的对象。</div>
</div>
</div>
<div class="sect3">
<h3 id="_对象存储">对象存储</h3>
<div class="paragraph">
<p>前文曾提及，你向 Git 仓库提交的所有对象都会有个头部信息一并被保存。
让我们略花些时间来看看 Git 是如何存储其对象的。
通过在 Ruby 脚本语言中交互式地演示，你将看到一个数据对象——本例中是字符串“what is up, doc?”——是如何被存储的。</p>
</div>
<div class="paragraph">
<p>可以通过 <code>irb</code> 命令启动 Ruby 的交互模式：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ irb
&gt;&gt; content = "what is up, doc?"
=&gt; "what is up, doc?"</code></pre>
</div>
</div>
<div class="paragraph">
<p>Git 首先会以识别出的对象的类型作为开头来构造一个头部信息，本例中是一个“blob”字符串。
接着 Git 会在头部的第一部分添加一个空格，随后是数据内容的字节数，最后是一个空字节（null byte）：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">&gt;&gt; header = "blob #{content.length}\0"
=&gt; "blob 16\u0000"</code></pre>
</div>
</div>
<div class="paragraph">
<p>Git 会将上述头部信息和原始数据拼接起来，并计算出这条新内容的 SHA-1 校验和。
在 Ruby 中可以这样计算 SHA-1 值——先通过 <code>require</code> 命令导入 SHA-1 digest 库，
然后对目标字符串调用 <code>Digest::SHA1.hexdigest()</code>：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">&gt;&gt; store = header + content
=&gt; "blob 16\u0000what is up, doc?"
&gt;&gt; require 'digest/sha1'
=&gt; true
&gt;&gt; sha1 = Digest::SHA1.hexdigest(store)
=&gt; "bd9dbf5aae1a3862dd1526723246b20206e5fc37"</code></pre>
</div>
</div>
<div class="paragraph">
<p>我们来比较一下 <code>git hash-object</code> 的输出。
这里使用了 <code>echo -n</code> 以避免在输出中添加换行。</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">$ echo -n "what is up, doc?" | git hash-object --stdin
bd9dbf5aae1a3862dd1526723246b20206e5fc37</code></pre>
</div>
</div>
<div class="paragraph">
<p>Git 会通过 zlib 压缩这条新内容。在 Ruby 中可以借助 zlib 库做到这一点。
先导入相应的库，然后对目标内容调用 <code>Zlib::Deflate.deflate()</code>：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">&gt;&gt; require 'zlib'
=&gt; true
&gt;&gt; zlib_content = Zlib::Deflate.deflate(store)
=&gt; "x\x9CK\xCA\xC9OR04c(\xCFH,Q\xC8,V(-\xD0QH\xC9O\xB6\a\x00_\x1C\a\x9D"</code></pre>
</div>
</div>
<div class="paragraph">
<p>最后，需要将这条经由 zlib 压缩的内容写入磁盘上的某个对象。
要先确定待写入对象的路径（SHA-1 值的前两个字符作为子目录名称，后 38 个字符则作为子目录内文件的名称）。
如果该子目录不存在，可以通过 Ruby 中的 <code>FileUtils.mkdir_p()</code> 函数来创建它。
接着，通过 <code>File.open()</code> 打开这个文件。最后，对上一步中得到的文件句柄调用 <code>write()</code> 函数，以向目标文件写入之前那条 zlib 压缩过的内容：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">&gt;&gt; path = '.git/objects/' + sha1[0,2] + '/' + sha1[2,38]
=&gt; ".git/objects/bd/9dbf5aae1a3862dd1526723246b20206e5fc37"
&gt;&gt; require 'fileutils'
=&gt; true
&gt;&gt; FileUtils.mkdir_p(File.dirname(path))
=&gt; ".git/objects/bd"
&gt;&gt; File.open(path, 'w') { |f| f.write zlib_content }
=&gt; 32</code></pre>
</div>
</div>
<div class="paragraph">
<p>我们用 <code>git cat-file</code> 查看一下该对象的内容：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">---
$ git cat-file -p bd9dbf5aae1a3862dd1526723246b20206e5fc37
what is up, doc?
---</code></pre>
</div>
</div>
<div class="paragraph">
<p>就是这样——你已创建了一个有效的 Git 数据对象。</p>
</div>
<div class="paragraph">
<p>所有的 Git 对象均以这种方式存储，区别仅在于类型标识——另两种对象类型的头部信息以字符串“commit”或“tree”开头，而不是“blob”。
另外，虽然数据对象的内容几乎可以是任何东西，但提交对象和树对象的内容却有各自固定的格式。</p>
</div>
</div>
<div id="nav"><a href="/book/zh/v2/Git-%E5%86%85%E9%83%A8%E5%8E%9F%E7%90%86-%E5%BA%95%E5%B1%82%E5%91%BD%E4%BB%A4%E4%B8%8E%E4%B8%8A%E5%B1%82%E5%91%BD%E4%BB%A4">prev</a> | <a href="/book/zh/v2/Git-%E5%86%85%E9%83%A8%E5%8E%9F%E7%90%86-Git-%E5%BC%95%E7%94%A8">next</a></div></div>
</div>

        </div>
      </div>
      <footer>
  <div class="site-source">
    <a href="/site">About this site</a><br>
    Patches, suggestions, and comments are welcome.
  </div>
  <div class="sfc-member">
    Git is a member of <a href="/sfc">Software Freedom Conservancy</a>
  </div>
</footer>
<a href="#top" class="no-js scrollToTop" id="scrollToTop" data-label="Scroll to top">
  <img src="/images/icons/chevron-up@2x.png" width="20" height="20" alt="scroll-to-top"/>
</a>
<script src="/assets/application-b09f91f7c527919e4bc194769429065537d64a7f73b9fe93b107afef32b02939.js"></script>

    </div>

</body>
</html>
